using Perfect.Marshal;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;

namespace editor.cfg
{
    public abstract class EditorReadWriter
    {
        public abstract int GetTypeId();


        public abstract void MarshalCompatible(Octets os);
        public abstract void UnmarshalCompatible(Octets os);

        public abstract void MarshalXml(XmlWriter ele);
        public abstract void UnmarshalXml(XmlElement ele);


        public void Load(string file)
        {
            if (file.EndsWith(".b"))
            {
                var os = new Octets(File.ReadAllBytes(file));
                UnmarshalCompatible(os);
            }
            else if (file.EndsWith(".xml"))
            {
                var doc = new XmlDocument();
                doc.Load(file);
                UnmarshalXml(doc.DocumentElement);
            }
            else
            {
                throw new Exception("文件后缀只支持 .bs 和 .xml");
            }
        }

        public void Save(string file)
        {
            if (file.EndsWith(".b"))
            {
                var os = new Octets();
                MarshalCompatible(os);
                File.WriteAllBytes(file, os.ToArray());
            }
            else if (file.EndsWith(".xml"))
            {
                using (var writer = XmlWriter.Create(file, new XmlWriterSettings() { Indent = true, IndentChars = "\t" }))
                {
                    writer.WriteStartDocument();

                    writer.WriteStartElement("data");

                    MarshalXml(writer);

                    writer.WriteEndElement();

                    writer.WriteEndDocument();
                }
            }
            else
            {
                throw new Exception("文件后缀只支持 .b 和 .xml");
            }
        }
    }


    public static class XmlWriterExtensions
    {
        public static void WriteBool(this XmlWriter os, bool x)
        {
            os.WriteString(x.ToString());
        }

        public static void WriteByte(this XmlWriter os, byte x)
        {
            os.WriteString(x.ToString());
        }
        public static void WriteDouble(this XmlWriter os, double x)
        {
            os.WriteString(x.ToString());
        }
        public static void WriteInt(this XmlWriter os, int x)
        {
            os.WriteString(x.ToString());
        }
        public static void WriteFloat(this XmlWriter os, float x)
        {
            os.WriteString(x.ToString());
        }
        public static void WriteLong(this XmlWriter os, long x)
        {
            os.WriteString(x.ToString());
        }
        public static void WriteShort(this XmlWriter os, short x)
        {
            os.WriteString(x.ToString());
        }
        public static void WriteString2(this XmlWriter os, string x)
        {
            os.WriteString(x);
        }
        public static void WriteOctets(this XmlWriter os, Octets x)
        {
            os.WriteString(x.ToString());
        }
        public static void WriteEnum<T>(this XmlWriter os, T x) where T : struct
        {
            os.WriteString(x.ToString());
        }
    }

    public static class XmlElementExtensions
    {
        public static bool ReadBool(this XmlElement ele)
        {
            return bool.Parse(ele.InnerText);
        }
        public static byte ReadByte(this XmlElement ele)
        {
            return byte.Parse(ele.InnerText);
        }
        public static double ReadDouble(this XmlElement ele)
        {
            return double.Parse(ele.InnerText);
        }
        public static int ReadInt(this XmlElement ele)
        {
            return int.Parse(ele.InnerText);
        }
        public static float ReadFloat(this XmlElement ele)
        {
            return float.Parse(ele.InnerText);
        }
        public static long ReadLong(this XmlElement ele)
        {
            return long.Parse(ele.InnerText);
        }
        public static Octets ReadOctets(this XmlElement ele)
        {
            return Octets.FromString(ele.InnerText);
        }
        public static string ReadString2(this XmlElement ele)
        {
            return ele.InnerText;
        }
        public static short ReadShort(this XmlElement ele)
        {
            return short.Parse(ele.InnerText);
        }
        public static T ReadEnum<T>(this XmlElement ele) where T : struct
        {
            //return Enum.Parse<T>(ele.InnerText);
            return (T)Enum.Parse(typeof(T), ele.InnerText);
        }

        public static List<XmlElement> GetChildren(this XmlElement parent)
        {
            return parent.ChildNodes.Cast<XmlElement>().Where(sub => sub.NodeType == XmlNodeType.Element).ToList();
        }
    }
}
